﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Denormalizers.Ef
{
    using ECommon.Components;
    using ENode.Infrastructure;

    using Domain.Accounts;
    using ECommon.IO;
    using ECommon.Logging;

    using Infrastructure;
    using System.Data.SqlClient;

    [Component]
    public class AccountDenormalizer : AbstractDenormalizer,
        IMessageHandler<NewAccountRegisteredEvent>,
        IMessageHandler<SignInAfterEvent>,
        IMessageHandler<SignOutAfterEvent>
    {
        private ILogger _logger;
        public AccountDenormalizer(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.Create(typeof(AccountDenormalizer).Name);
        }

        public Task<AsyncTaskResult> HandleAsync(NewAccountRegisteredEvent evnt)
        {
            _logger.InfoFormat("NewAccountRegisteredEvent, Id:{0}, Name：{1}, Version: {2}", evnt.AggregateRootId, evnt.Name, evnt.Version);
            //return Task.FromResult(AsyncTaskResult.Success);

            using (Repository.EntityFramework.Accounts.DataContext db = 
                new Repository.EntityFramework.Accounts.DataContext())
            {
                db.AccountInfo.Add(new Repository.EntityFramework.Accounts.AccountInfo
                {
                    CreatedOn = evnt.Timestamp,
                    Id = evnt.AggregateRootId,
                    Name = evnt.Name,
                    Password = evnt.Password,
                    Version = evnt.Version
                });

                try
                {
                    db.SaveChanges();
                }
                catch (SqlException ex)
                {
                    if (ex.Number != 2627)  //主键冲突，忽略即可；出现这种情况，是因为同一个消息的重复处理
                    {
                        throw;
                    }
                }

                return Task.FromResult(AsyncTaskResult.Success);
            }
        }

        public Task<AsyncTaskResult> HandleAsync(SignInAfterEvent message)
        {
            _logger.InfoFormat("SignInAfterEvent, Id:{0}, AggregateRootId：{1}, Version: {2}", message.Id, message.AggregateRootId, message.Version);
            using (Repository.EntityFramework.Accounts.DataContext db = new Repository.EntityFramework.Accounts.DataContext())
            {
                var m = db.AccountInfo.Where(x => x.Id == message.AggregateRootId && x.Version == message.Version - 1).SingleOrDefault();

                m.TotalSignInTimes = message.StatisticInfo.TotalTimes;
                m.LastSignInTime = message.StatisticInfo.LastTime;
                m.LastIpAddress = message.StatisticInfo.LastIpAddress;
                m.LastSessionId = message.StatisticInfo.LastSessionId;
                m.Version = message.Version;


                // 放到这个地方，只是做了一个记录，少了个业务的感觉。因该有一个显示的记录登录日志的领域方法。将这个方法的调用放到领域中去? 类似于accountIndex一样?
                db.AccountLog.Add(new Repository.EntityFramework.Accounts.AccountLog
                {
                    AccountId = m.Id,
                    AccountName = m.Name,
                    LogIn = DateTime.Now,
                    //Id = 0,
                    IpAddress = m.LastIpAddress,
                    LogOff = null,
                    SessionId = m.LastSessionId,
                });

                db.SaveChanges();
            }
            return Task.FromResult(AsyncTaskResult.Success);
        }

        public Task<AsyncTaskResult> HandleAsync(SignOutAfterEvent message)
        {
            _logger.InfoFormat("SignOutAfterEvent, Id:{0}, AggregateRootId：{1}, Version: {2}", message.Id, message.AggregateRootId, message.Version);
            using (Repository.EntityFramework.Accounts.DataContext db = new Repository.EntityFramework.Accounts.DataContext())
            {
                var m = db.AccountInfo.Where(x => x.Id == message.AggregateRootId && x.Version == message.Version - 1).SingleOrDefault();

                m.TotalSignOutTimes = message.StatisticInfo.TotalTimes;
                m.LastSignOutTime = message.StatisticInfo.LastTime;
                m.Version = message.Version;


                var log = db.AccountLog.Where(x => x.AccountId == m.Id && x.SessionId == message.StatisticInfo.LastSessionId).SingleOrDefault();
                if (log!=null)
                {
                    log.LogOff = DateTime.Now;
                }
                db.SaveChanges();
            }
            return Task.FromResult(AsyncTaskResult.Success);
        }
    }
}
